package org.example.clouddemo.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys; // 修正：这是报错'Keys'找不到的原因
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private long expiration;

    // 修正：从字符串密钥生成一个安全的SecretKey
    private SecretKey getSecretKey() {
        return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 从Token中获取UUID (JWT ID)
     * @param token JWT
     * @return UUID
     */
    public String getUuidFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.getId() : null;
    }

    /**
     * 从Token中获取Claims
     * @param token JWT
     * @return Claims
     */
/*    private Claims getClaimsFromToken(String token) {
        try {
            // 修正：使用了新的API Jwts.parserBuilder()
            return Jwts.parserBuilder()
                    .setSigningKey(getSecretKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            // Token过期、签名无效等都会导致异常
            // 在生产环境中，这里应该记录日志
            return null;
        }
    }*/

    /**
     * 从Token中获取Claims (使用兼容性更好的旧版API)
     * @param token JWT
     * @return Claims
     */
    private Claims getClaimsFromToken(String token) {
        try {
            // 使用旧版API：Jwts.parser()，它在所有版本中都可用
            return Jwts.parser()
                    .setSigningKey(getSecretKey()) // 设置签名密钥
                    .parseClaimsJws(token)         // 解析token
                    .getBody();                    // 获取载荷
        } catch (ExpiredJwtException e) {
            // Token已过期，这是正常情况，返回null让后续逻辑处理
            // 在生产环境中，可以记录日志：log.warn("JWT token is expired: {}", e.getMessage());
            return null;
        } catch (UnsupportedJwtException e) {
            // Token结构不受支持
            // log.error("Unsupported JWT token", e);
            return null;
        } catch (MalformedJwtException e) {
            // Token格式错误
            // log.error("Invalid JWT token", e);
            return null;
        } catch (SignatureException e) {
            // 签名验证失败
            // log.error("Invalid JWT signature", e);
            return null;
        } catch (IllegalArgumentException e) {
            // Token参数非法
            // log.error("JWT token compact of handler are invalid", e);
            return null;
        }
    }

    /**
     * 【核心方法】创建JWT
     *
     * @param claims  要放入payload的自定义信息
     * @param subject JWT的主题，我们用它来存放UUID
     * @return 生成的JWT字符串
     */
    private String createToken(Map<String, Object> claims, String subject) {
        // 获取当前时间
        Date now = new Date(System.currentTimeMillis());
        // 计算过期时间
        Date expirationDate = new Date(now.getTime() + expiration * 1000);

        return Jwts.builder()
                .setClaims(claims)       // 设置自定义载荷
                .setSubject(subject)     // 设置主题（UUID）
                .setIssuedAt(now)        // 设置签发时间
                .setExpiration(expirationDate) // 设置过期时间
                .signWith(SignatureAlgorithm.HS512, getSecretKey()) // 使用HS512算法和密钥签名
                .compact();              // 构建并返回字符串
    }


    /**
     * 根据UUID生成Token
     * @param uuid 唯一标识
     * @return JWT
     */
    public String generateToken(String uuid) {
        Map<String, Object> claims = new HashMap<>();
        // 你也可以在这里存放其他非敏感信息
        // claims.put("role", "user");

        // 修正：使用了新的API
        return Jwts.builder()
                .setClaims(claims)
                .setId(uuid) // 将UUID作为JTI (JWT ID)，这是标准的做法
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS256, getSecretKey()) // 修正：signWith的用法
                .compact();
    }

    /**
     * 验证Token是否有效（未过期且签名正确）
     * @param token JWT
     * @return boolean
     */
    public boolean validateToken(String token) {
        // 只要能成功解析出claims，就说明token是有效的
        return getClaimsFromToken(token) != null;
    }




    /**
     * 获取Token的过期时间
     * @return long (in milliseconds)
     */
    public long getExpiration() {
        return expiration;
    }
}
